package com.xlh.enums.courseTest;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xlh.dto.courseTest.AnswerSheetDTO;
import com.xlh.dto.courseTest.AnswerSheetTypeDTO;
import com.xlh.dto.courseTest.ReportDTO;
import com.xlh.dto.courseTest.paper.BasePaperDTO;
import com.xlh.dto.courseTest.paper.ExperimentPaperDTO;
import com.xlh.dto.courseTest.paper.StudentPaperDTO;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.courseTest.CourseTestPaper;
import com.xlh.pojo.courseTest.CourseTestPaperAnswer;
import com.xlh.pojo.courseTest.CourseTestPaperAnswerSheet;
import com.xlh.pojo.courseTest.CourseTestPaperQuestion;
import com.xlh.service.courseTest.ExperimentService;
import com.xlh.service.courseTest.PaperAnswerService;
import com.xlh.service.courseTest.PaperAnswerSheetService;
import com.xlh.service.courseTest.PaperQuestionService;
import com.xlh.util.SpringContextUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zhr 2019/4/17
 */
@Getter
@AllArgsConstructor
public enum AnswerSheetStatusEnum {
    BASE_TEST(1, "理论题") {
        @Override
        public BasePaperDTO paperDetails(
                Long userId, CourseTestPaper paper, Long paperId, Long questionId,
                CourseTestPaperAnswerSheet answerSheet,
                List<CourseTestPaperQuestion> questionList,
                Long courseId, Long timeLeft) {
            // 查询题干信息
            BasePaperDTO result = new BasePaperDTO();

            if (questionId == null) {
                questionId = questionList.get(0).getId();
            }

            CourseTestPaperQuestion question = questionService.selectQuestionById(questionId);

            boolean isChoice = Objects.equals(question.getType(), QuestionTypeEnum.CHOICE.getCode());
            List<CourseTestPaperAnswer> questionAnswerList = isChoice ?
                    answerService.selectAnswerList(Lists.newArrayList(questionId), paperId) : Lists.newArrayList();

            List<AnswerSheetDTO> answerSheetList = answerSheetService.get(paperId, answerSheet.getId());
            List<AnswerSheetTypeDTO> answerSheetTypeList;
            if (CollectionUtils.isEmpty(answerSheetList)) {
                answerSheetTypeList = JSONArray.parseArray(answerSheet.getContent(), AnswerSheetTypeDTO.class);
                answerSheetList = AnswerSheetDTO.parse(answerSheetTypeList);
                answerSheetService.put(paperId, answerSheet.getId(), answerSheetList);
            } else {
                answerSheetTypeList = AnswerSheetTypeDTO.transform(answerSheetList);
            }

            Object userAnswer = findUserAnswer(answerSheetList, question.getId());

            result.setPaperName(paper.getPaperName());
            result.setStatus(answerSheet.getPaperStatus());
            result.setPreview(findPrev(questionList, question));
            result.setNext(findNext(questionList, question));
            return result.transform(questionList, question, questionAnswerList, answerSheet, answerSheetTypeList, userAnswer, timeLeft);
        }

        private Object findUserAnswer(List<AnswerSheetDTO> answerSheetList, Long questionId) {
            for (AnswerSheetDTO dto : answerSheetList) {
                if (com.google.common.base.Objects.equal(dto.getId(), questionId)) {
                    return dto.getAnswer();
                }
            }
            return null;
        }
    },
    EXPERIMENT_TEST(2, "实验题") {
        @Override
        public ExperimentPaperDTO paperDetails(
                Long userId, CourseTestPaper paper, Long paperId, Long questionId,
                CourseTestPaperAnswerSheet answerSheet,
                List<CourseTestPaperQuestion> questionList,
                Long courseId, Long timeLeft) {
            ExperimentPaperDTO result = new ExperimentPaperDTO();

            questionList = questionList.stream().filter(question -> Objects.equals(question.getType(), QuestionTypeEnum.EXPERIMENT.getCode())).collect(Collectors.toList());
            if (questionId == null) {
                if (CollectionUtils.isEmpty(questionList)) {
                    answerSheetService.setUpdate(answerSheet, null, AnswerSheetStatusEnum.READING);
                    // 无实验题,直接退出
                    throw new GlobalException("本试卷无实验题,已自动变更交卷状态");
                }
                questionId = questionList.get(0).getId();
            }

            if (answerSheetService.get(paperId, answerSheet.getId()) == null) {
                answerSheetService.put(paperId, answerSheet.getId(), Lists.newArrayList());
            }

            CourseTestPaperQuestion question = questionService.selectQuestionById(questionId);

            // 实验报告为空时，异步插入一条新纪录,并返回一个默认对象
            ReportDTO report = experimentService.selectInsertTest(answerSheet.getId(), questionId, userId, courseId);

            result.setPaperName(paper.getPaperName());
            result.setStatus(answerSheet.getPaperStatus());
            result.setNext(findNext(questionList, question));
            result.setPreview(findPrev(questionList, question));
            return result.transform(report, timeLeft, answerSheet, question);
        }
    },
    READING(3, "正在批阅") {
        @Override
        public StudentPaperDTO paperDetails(
                Long userId, CourseTestPaper paper, Long paperId, Long questionId, CourseTestPaperAnswerSheet answerSheet,
                List<CourseTestPaperQuestion> questionList, Long courseId, Long timeLeft
        ) {
            throw new GlobalException("已交卷,不可再进行考试");
        }
    },
    READ(4, "已批阅") {
        @Override
        public StudentPaperDTO paperDetails(
                Long userId, CourseTestPaper paper, Long paperId, Long questionId, CourseTestPaperAnswerSheet answerSheet,
                List<CourseTestPaperQuestion> questionList, Long courseId, Long timeLeft
        ) {
            throw new GlobalException("已交卷,不可再进行考试");
        }
    };

    private final Integer status;
    private final String message;

    private static Map<Integer, AnswerSheetStatusEnum> statusLookup = Maps.newHashMap();

    static {
        for (AnswerSheetStatusEnum statusEnum : AnswerSheetStatusEnum.values()) {
            statusLookup.put(statusEnum.getStatus(), statusEnum);
        }
    }

    private static PaperQuestionService questionService = SpringContextUtil.getBean(PaperQuestionService.class);
    private static PaperAnswerService answerService = SpringContextUtil.getBean(PaperAnswerService.class);
    private static PaperAnswerSheetService answerSheetService = SpringContextUtil.getBean(PaperAnswerSheetService.class);
    private static ExperimentService experimentService = SpringContextUtil.getBean(ExperimentService.class);

    public static AnswerSheetStatusEnum forCode(Integer code) {
        return statusLookup.get(code);
    }

    /**
     * 找到列表后一元素id
     */
    private static Long findNext(List<CourseTestPaperQuestion> questionList, CourseTestPaperQuestion question) {
        for (int i = 0; i < questionList.size(); i++) {
            if (Objects.equals(question.getId(), questionList.get(i).getId()) && i + 1 < questionList.size()) {
                return questionList.get(i + 1).getId();
            }
        }
        return null;
    }

    /**
     * 找到列表的前一元素id
     */
    private static Long findPrev(List<CourseTestPaperQuestion> questionList, CourseTestPaperQuestion question) {
        for (int i = 0; i < questionList.size(); i++) {
            if (Objects.equals(question.getId(), questionList.get(i).getId()) && i - 1 >= 0) {
                return questionList.get(i - 1).getId();
            }
        }
        return null;
    }

    public boolean isBase() {
        return Objects.equals(this, BASE_TEST);
    }

    public boolean isExperiment() {
        return Objects.equals(this, EXPERIMENT_TEST);
    }

    public abstract StudentPaperDTO paperDetails(
            Long userId, CourseTestPaper paper, Long paperId, Long questionId, CourseTestPaperAnswerSheet answerSheet,
            List<CourseTestPaperQuestion> questionList, Long courseId, Long timeLeft
    );
}
